package com.hulden.rpc.server;

import com.hulden.rpc.common.bean.RpcRequest;
import com.hulden.rpc.common.bean.RpcResponse;
import com.hulden.rpc.common.util.StringUtil;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * RPC 服务端处理器（用于处理 RPC 请求）
 *
 * @author hugo
 * @since 1.0.0
 */
public class RpcServerHandler extends SimpleChannelInboundHandler<RpcRequest> {
    private static final Logger log = LoggerFactory.getLogger(RpcServerHandler.class);

    private final Map<String,Object> handlerMap;

    public RpcServerHandler(Map<String,Object> handlerMap){
        this.handlerMap = handlerMap;
    }

    @Override
    protected void channelRead0(final ChannelHandlerContext ctx, RpcRequest request) throws Exception {
        RpcResponse response = new RpcResponse();
        response.setRequestId(request.getRequestId());
        try{
            Object result = handle(request);
            response.setResult(result);
        }
        catch (Exception e){
            log.error("handle result failure",e);
            response.setException(e);
        }

        //写入RPC 响应对象并自动关闭连接
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }

    private Object handle(RpcRequest request) throws InvocationTargetException {
        //获取服务对象
        String serviceName = request.getInterfaceName();
        String serviceVersion =request.getServiceVersion();
        if(StringUtil.isNotEmpty(serviceVersion)){
            serviceName += "-" + serviceVersion;
        }

        Object serviceBean = handlerMap.get(serviceName);
        if(serviceBean == null){
            throw new RuntimeException(String.format("can not find service bean by key: %s",serviceName));
        }

        Class<?> serviceClass = serviceBean.getClass();
        String methodName = request.getMethodName();
        Class<?>[] parameterTypes = request.getParameterTypes();
        Object[] parameters = request.getParameters();

        //执行反射调用
//        Method method = serviceClass.getMethod(methodName,parameterTypes);
//        ((Method) method).setAccessible(true);
//        return method.invoke(serviceBean,parameters);

        //使用CGLib执行反射调用
        FastClass fastClass = FastClass.create(serviceClass);
        FastMethod fastMethod = fastClass.getMethod(methodName,parameterTypes);
        return fastMethod.invoke(serviceBean,parameters);


    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("server caught exceoption",cause);
        ctx.close();
    }
}
